library(tidyverse)
library(eph)
library(spatstat)
options(scipen = 9999) #la opción scipen modifica el límite en el que los números decimales pasan a expresarse con notación científica. En este caso, lo utilizamos para evitar la notación científica.
options(dplyr.summarise.inform = FALSE)
En la clase de hoy vamos a explorar nuevas formas de procesar una base de datos y visualizar nuestros resultados.
En particular, vamos a introducir el paquete plotly para generar visualizaciones interactivas.
Por último, vamos a trabajar con funciones e iteraciones para escalar nuestra capacidad de análisis de datos y presentación de resultados.
La visualización interactiva va a permitir que los usuarios de nuestras visualizaciones puedan explorar nuestros resultados con mayor libertad. Es decir, van a permitir que cada usuario pueda analizar con mayor detalle lo que más le interesa.
Vamos a volver a trabajar con la base de EPH para encontrar la brecha salarial entre varones y mujeres para cada sector productivo, y luego vamos a graficarlo interactivamente.
base <- eph::get_microdata(year = 2019,
trimester = 1,
type = "individual",
destfile = "clase6/eph_2019_T1.rds") %>%
organize_caes()%>% #recodifica la variable que indica el sector de la ocupación
select(ESTADO,"SEXO" = CH04, "Ing_Ocup_Principal"= P21, PONDIIO,caes_eph_label, "Horas" = PP3E_TOT, PONDERA) %>%
mutate(ESTADO = case_when(ESTADO == 1 ~ "Ocupado",
ESTADO == 2 ~ "Desocupado",
ESTADO == 3 ~ "Inactivo",
ESTADO == 4 ~ "Menor de 10 años"),
SEXO = case_when(SEXO == 1 ~ "Varones",
SEXO == 2 ~ "Mujeres")) %>%
filter(Ing_Ocup_Principal != -9) %>% #excluimos el valor de no respuesta
filter(ESTADO == "Ocupado")
Calculamos el ingreso medio de los trabajadores de cada sexo y sector, y luego la brecha. También vamos a tener en cuenta en qué sectores las mujeres tienen una participación mayor.
#Aclaración: el ponderador para la variable de ingreso de la ocupación proncipal es PONDIIO
ingresos <- base %>%
filter(Ing_Ocup_Principal > 0) %>% #excluimos a personas con ingreso = 0
group_by(SEXO,caes_eph_label) %>%
summarise(Ingreso_medio = weighted.mean(Ing_Ocup_Principal,PONDIIO, na.rm = T)) %>% #al igual que en otras funciones, en este caso na.rm excluye los valores faltantes del promedio ponderado
pivot_wider(id_cols = caes_eph_label, names_from = SEXO, values_from = Ingreso_medio) %>%
mutate(brecha = ((Varones-Mujeres)/Varones))
ingresos
## # A tibble: 14 x 4
## caes_eph_label Mujeres Varones brecha
## <fct> <dbl> <dbl> <dbl>
## 1 Actividades primarias 26607. 38218. 0.304
## 2 Industria manufacturera 15351. 23005. 0.333
## 3 Construccion 17316. 15654. -0.106
## 4 Comercio 14916. 20068. 0.257
## 5 Hoteles y restaurantes 11952. 15263. 0.217
## 6 Transporte, almacenamiento y comunicaciones 24106. 26564. 0.0925
## 7 Servicios financieros, de alquiler y empresariales 23430. 27491. 0.148
## 8 Administracion publica, defensa y seguridad social 25803. 27890. 0.0748
## 9 Ensenanza 19573. 22295. 0.122
## 10 Servicios sociales y de salud 24354. 34723. 0.299
## 11 Servicio domestico 6844. 5779. -0.184
## 12 Otros servicios comunitarios, sociales y personales 10810. 20931. 0.484
## 13 Otras ramas 29610. 26477. -0.118
## 14 Actividades no bien especificadas 23731. 28258. 0.160
feminizacion <- base %>%
group_by(SEXO,caes_eph_label) %>%
summarise(Casos = sum(PONDERA)) %>%
ungroup() %>%
group_by(caes_eph_label) %>%
mutate(Total = sum(Casos),
feminizacion = (Casos/Total)*100) %>%
filter(SEXO == "Mujeres") %>%
select(caes_eph_label, feminizacion)
feminizacion
## # A tibble: 14 x 2
## # Groups: caes_eph_label [14]
## caes_eph_label feminizacion
## <fct> <dbl>
## 1 Actividades primarias 14.6
## 2 Industria manufacturera 30.8
## 3 Construccion 2.73
## 4 Comercio 41.6
## 5 Hoteles y restaurantes 45.8
## 6 Transporte, almacenamiento y comunicaciones 14.5
## 7 Servicios financieros, de alquiler y empresariales 42.5
## 8 Administracion publica, defensa y seguridad social 41.6
## 9 Ensenanza 75.9
## 10 Servicios sociales y de salud 66.5
## 11 Servicio domestico 96.4
## 12 Otros servicios comunitarios, sociales y personales 44.1
## 13 Otras ramas 16.8
## 14 Actividades no bien especificadas 23.2
ingresos <- ingresos %>%
left_join(.,feminizacion, by = "caes_eph_label")
ingresos
## # A tibble: 14 x 5
## caes_eph_label Mujeres Varones brecha feminizacion
## <fct> <dbl> <dbl> <dbl> <dbl>
## 1 Actividades primarias 26607. 38218. 0.304 14.6
## 2 Industria manufacturera 15351. 23005. 0.333 30.8
## 3 Construccion 17316. 15654. -0.106 2.73
## 4 Comercio 14916. 20068. 0.257 41.6
## 5 Hoteles y restaurantes 11952. 15263. 0.217 45.8
## 6 Transporte, almacenamiento y comunicaci~ 24106. 26564. 0.0925 14.5
## 7 Servicios financieros, de alquiler y em~ 23430. 27491. 0.148 42.5
## 8 Administracion publica, defensa y segur~ 25803. 27890. 0.0748 41.6
## 9 Ensenanza 19573. 22295. 0.122 75.9
## 10 Servicios sociales y de salud 24354. 34723. 0.299 66.5
## 11 Servicio domestico 6844. 5779. -0.184 96.4
## 12 Otros servicios comunitarios, sociales ~ 10810. 20931. 0.484 44.1
## 13 Otras ramas 29610. 26477. -0.118 16.8
## 14 Actividades no bien especificadas 23731. 28258. 0.160 23.2
Tal como se refleja en nuestros resultados, las brechas de ingresos tienden a estar a favor de los varones. No obstante, es interesante vincular este análisis con la tasa de feminización para interpretar casos como el del sector de la Construcción, donde la mayor parte de los trabajadores son varones, pero las mujeres participan en roles que requieren una mayor calificación (trabajo de oficina, arquitectas, etc.): esto tiene como resultado una brecha de ingresos a favor de las mujeres.
Para graficar nuestros resultados, vamos a recurrir al paquete plotly. Este paquete nos ayuda a crear gráficos interactivos (y puede utilizarse en combinación con ggplot para transformar un gráfico no interactivo en un gráfico interactivo).
library(plotly)
En nuestro gráfico, vamos a graficar el ingreso medio de cada sector productivo para trabajadores de cada sexo, coloreando cada burbuja de acuerdo con la magnitud de la brecha, y determinando el tamaño de la burbuja según la proporción de trabajadoras mujeres en el sector.
#La sintaxis es un poco distinta a la de ggplot, más abajo podemos ver cómo recurrir a ella si nos resulto más cómoda
plot_ly(ingresos, x = ~Mujeres, y = ~Varones,
color = ~brecha, colors = 'Spectral',
type = 'scatter', mode = 'markers', marker = list(size = ~feminizacion, opacity = 0.9),
hoverinfo = 'text',
text = ~paste(caes_eph_label, '<br>Mujeres:', paste0("$",round(Mujeres,1)), '<br>Varones:', paste0("$",round(Varones,1)), '<br>Brecha:', paste0(round(brecha*100,1), "%"), '<br>Proporción de trabajadoras mujeres:', paste0(round(feminizacion,1), "%"))
) %>%
layout(title = 'Ingreso medio y brecha salarial por sector productivo',
xaxis = list(showgrid = FALSE),
yaxis = list(showgrid = FALSE),
font = list(family ="Times New Roman"))
Prueben pasar el mouse por encima del gráfico, moverlo, hacer zoom, etc.
¿Qué análisis podemos hacer de la información representada?
La función ggplotly() convierte nuestros ggplots en plotly. De esta forma, podemos tomar cualquiera de las visualizaciones que aprendimos a hacer la clase pasada y hacerla interactiva.
Por ejemplo:
feminizacion <- base %>%
group_by(SEXO,caes_eph_label) %>%
summarise(Casos = sum(PONDERA)) %>%
ungroup() %>%
group_by(caes_eph_label) %>%
mutate(Total = sum(Casos),
feminizacion = (Casos/Total)*100)%>%
filter(SEXO == "Mujeres") %>%
select(caes_eph_label, feminizacion)
feminizacion
## # A tibble: 14 x 2
## # Groups: caes_eph_label [14]
## caes_eph_label feminizacion
## <fct> <dbl>
## 1 Actividades primarias 14.6
## 2 Industria manufacturera 30.8
## 3 Construccion 2.73
## 4 Comercio 41.6
## 5 Hoteles y restaurantes 45.8
## 6 Transporte, almacenamiento y comunicaciones 14.5
## 7 Servicios financieros, de alquiler y empresariales 42.5
## 8 Administracion publica, defensa y seguridad social 41.6
## 9 Ensenanza 75.9
## 10 Servicios sociales y de salud 66.5
## 11 Servicio domestico 96.4
## 12 Otros servicios comunitarios, sociales y personales 44.1
## 13 Otras ramas 16.8
## 14 Actividades no bien especificadas 23.2
#paleta de colores divina!
library(wesanderson)
plot_estatico <- feminizacion %>%
ggplot(.,aes(x = fct_reorder(caes_eph_label,feminizacion), y = feminizacion,
fill = feminizacion,
#para que el hovertext nos quede como queremos en el siguiente paso
text = paste(caes_eph_label, '<br>Proporción de trabajadoras mujeres:', paste0(round(feminizacion,1), "%"))
)
)+
geom_col(alpha = 0.9)+
theme_minimal()+
coord_flip()+
labs(title = 'Tasa de feminización de las ramas de actividad',
x="",y="")+
scale_y_continuous(labels = function(x) paste0(x,"%"))+
scale_x_discrete(labels = function(x) str_wrap(x,25))+
scale_fill_gradientn(colours = wes_palette("Zissou1", 100, type = "continuous")) +
guides(fill = "none")
plot_estatico
#lo hacemos interactivo
ggplotly(plot_estatico,
tooltip = "text") %>%
layout(font = list(family ="Times New Roman"))
La iteración y las funciones nos van a permitir reducir la duplicación en el código (copiar y pegar las mismas instrucciones).
¿Por qué reducir la duplicación?
Es más fácil entender tu código (para vos en otro momento, o para un tercero).
Es más simple realizar cambios y encontrar errores.
Además, van a potenciar nuestro trabajo con R, permitiéndonos escalar la cantidad de procesamientos y visualizaciones que podemos obtener a partir del análisis de una base de datos en muy poco tiempo.
La iteración es una herramienta para repetir la misma tarea con múltiples inputs (variables, conjuntos de datos, etc.).
Un loop es una estructura de código que nos permite aplicar iterativamente un mismo conjunto de comandos, variando el valor de una variable. Su estructura general es la siguiente:
for (variable in vector) {
#Operaciones
}
El nombre que definamos para la variable debe ser el mismo que utilicemos para realizar las operaciones dentro del loop, pero puede ser cualquiera (x,i,planta,supercalifragil, etc).
Por ejemplo:
for (x in 1:5) {
print(x*x)
}
## [1] 1
## [1] 4
## [1] 9
## [1] 16
## [1] 25
Lo que hizo el código fue crear una variable x, que fue tomando los valores 1, 2, 3, 4 y 5, y en cada caso multiplicándose por sí misma.
En nuestro loop pueden intervenir también objetos que hayamos definido previamente.
Por ejemplo:
b <- 10
for (x in 1:5) {
print(x+b)
}
## [1] 11
## [1] 12
## [1] 13
## [1] 14
## [1] 15
Una herramienta que vamos a utilizar mucho es la función seq(), que permite generar una secuencia de números (que vamos a utilizar para iterar). Por default, si ingresamos un único número como argumento, genera una secuencia desde 1 hasta ese número.
seq(3)
## [1] 1 2 3
for (i in (seq(3))) {
print(i)
}
## [1] 1
## [1] 2
## [1] 3
¿Cuándo podríamos usar esto? En operaciones de subsetting o slicing
#defino el vector
vec <- c("a","b","c")
#¿cuántos elementos tiene?
length(vec)
## [1] 3
#Convierto cada elemento al mismo elemento en mayúscula
for (letra in (seq(length(vec)))) {
vec[letra] <- toupper(vec[letra])
}
#¿Cómo quedó?
vec
## [1] "A" "B" "C"
¿Qué pasó? Nuestro loop fue avanzando sobre los elementos de vec, reemplazándolos por el mismo valor en mayúscula. Por ejemplo, al vec[1] = “a”, lo transformó en “A”.
Veamos cómo puede ser útil para un procesamiento.
Si tenemos una base de datos con información sobre distintos tipos de población, podemos querer generar una medida resumen para cada segmento de la población.
Por ejemplo, supongamos que queremos llevar a cabo un análisis más detallado de la distribución de los ingresos por sexo para cada rama de actividad:
vector_valores <- unique(base$caes_eph_label)
#En esta lista vamos a guardar nuestros resultados
resultados <- list()
for (valor in (seq(length(vector_valores)))) {
tabla_resumen <- base %>%
filter(caes_eph_label == vector_valores[valor]) %>%
filter(Ing_Ocup_Principal > 0) %>%
group_by(SEXO) %>%
summarise(sector = unique(caes_eph_label),
max_ing = max(Ing_Ocup_Principal, na.rm = T),
min_ing = min(Ing_Ocup_Principal, na.rm = T),
media_ing = weighted.mean(Ing_Ocup_Principal, PONDIIO, na.rm = T),
mediana_ing = weighted.median(Ing_Ocup_Principal, PONDIIO, na.rm = T))
resultados[[valor]] <- tabla_resumen
#En este caso, estamos usando “valor” como iterador, en el sentido de índice dentro de un vector (vector_valores). Si en cada iteración, además de nuestro procesamiento imprimos "valor", obtenemos la serie de índices.
print(valor)
#Es decir, no estamos recurriendo directamente a cada uno de los valores del vector, sino que cada sector se corresponde con uno de estos índices. Los podemos obtener (por ejemplo) así:
print(unique(as.character(tabla_resumen$sector)))
#Al iterar, print puede ser muy útil para entender qué está pasando (especialmente si los resultados no son los que esperamos!).
}
## [1] 1
## [1] "Actividades primarias"
## [1] 2
## [1] "Construccion"
## [1] 3
## [1] "Servicios financieros, de alquiler y empresariales"
## [1] 4
## [1] "Transporte, almacenamiento y comunicaciones"
## [1] 5
## [1] "Ensenanza"
## [1] 6
## [1] "Administracion publica, defensa y seguridad social"
## [1] 7
## [1] "Comercio"
## [1] 8
## [1] "Servicio domestico"
## [1] 9
## [1] "Industria manufacturera"
## [1] 10
## [1] "Hoteles y restaurantes"
## [1] 11
## [1] "Otros servicios comunitarios, sociales y personales"
## [1] 12
## [1] "Servicios sociales y de salud"
## [1] 13
## [1] "Otras ramas"
## [1] 14
## [1] "Actividades no bien especificadas"
#Veamos una de las tablas que generamos:
resultados[[3]]
## # A tibble: 2 x 6
## SEXO sector max_ing min_ing media_ing mediana_ing
## <chr> <fct> <int> <int> <dbl> <dbl>
## 1 Mujeres Servicios financieros, de alqui~ 100000 450 23430. 20000
## 2 Varones Servicios financieros, de alqui~ 300000 300 27491. 22000
También podemos presentar nuestros resultados de una manera más amigable con quien está leyendo, o listo para copiar e incluir en un informe:
for (valor in (seq(length(vector_valores)))) {
print(paste0("Para el sector ", unique(resultados[[valor]]$sector), ", el ingreso máximo alcanzado por un varón fue de $", resultados[[valor]]$max_ing[resultados[[valor]]$SEXO == "Varones"], ". Para las mujeres, por otro lado, fue de $", resultados[[valor]]$max_ing[resultados[[valor]]$SEXO == "Mujeres"]))
}
## [1] "Para el sector Actividades primarias, el ingreso máximo alcanzado por un varón fue de $250000. Para las mujeres, por otro lado, fue de $80000"
## [1] "Para el sector Construccion, el ingreso máximo alcanzado por un varón fue de $200000. Para las mujeres, por otro lado, fue de $75000"
## [1] "Para el sector Servicios financieros, de alquiler y empresariales, el ingreso máximo alcanzado por un varón fue de $300000. Para las mujeres, por otro lado, fue de $100000"
## [1] "Para el sector Transporte, almacenamiento y comunicaciones, el ingreso máximo alcanzado por un varón fue de $290000. Para las mujeres, por otro lado, fue de $70000"
## [1] "Para el sector Ensenanza, el ingreso máximo alcanzado por un varón fue de $100000. Para las mujeres, por otro lado, fue de $70000"
## [1] "Para el sector Administracion publica, defensa y seguridad social, el ingreso máximo alcanzado por un varón fue de $150000. Para las mujeres, por otro lado, fue de $200000"
## [1] "Para el sector Comercio, el ingreso máximo alcanzado por un varón fue de $300000. Para las mujeres, por otro lado, fue de $100000"
## [1] "Para el sector Servicio domestico, el ingreso máximo alcanzado por un varón fue de $15000. Para las mujeres, por otro lado, fue de $40500"
## [1] "Para el sector Industria manufacturera, el ingreso máximo alcanzado por un varón fue de $200000. Para las mujeres, por otro lado, fue de $200000"
## [1] "Para el sector Hoteles y restaurantes, el ingreso máximo alcanzado por un varón fue de $60000. Para las mujeres, por otro lado, fue de $35000"
## [1] "Para el sector Otros servicios comunitarios, sociales y personales, el ingreso máximo alcanzado por un varón fue de $250000. Para las mujeres, por otro lado, fue de $80000"
## [1] "Para el sector Servicios sociales y de salud, el ingreso máximo alcanzado por un varón fue de $390000. Para las mujeres, por otro lado, fue de $150000"
## [1] "Para el sector Otras ramas, el ingreso máximo alcanzado por un varón fue de $70000. Para las mujeres, por otro lado, fue de $60000"
## [1] "Para el sector Actividades no bien especificadas, el ingreso máximo alcanzado por un varón fue de $100000. Para las mujeres, por otro lado, fue de $80000"
Retomamos lo introducido en la clase 2: la función es una forma de encapsular una serie de operaciones a las que vayamos a recurrir más de una vez, esta es su estructura general:
fun_ej <-function(argumentos){
#[se hace algún cómputo]
}
En este caso, vamos a utilizar esta herramienta -en conjunto con la iteración- para generar una serie de gráficos donde se visualice la distribución de los ingresos de las mujeres y los varones que se desempeñan en cada sector productivo de acuerdo con las horas que trabajan por semana.
Primero, vamos a generar los datos que vamos a graficar:
vector_valores <- unique(base$caes_eph_label)
#En esta lista vamos a guardar nuestros resultados
datos_graf <- list()
for (valor in (seq(length(vector_valores)))) {
tabla_resumen <- base %>%
filter(caes_eph_label == vector_valores[valor]) %>%
filter(Ing_Ocup_Principal > 0) %>%
filter(Horas > 0) %>%
filter(Horas != 999) %>%
group_by(SEXO, Ing_Ocup_Principal, Horas) %>%
summarise(Casos = sum(PONDIIO, na.rm = T),
sector = unique(caes_eph_label))
datos_graf[[valor]] <- tabla_resumen
}
Veamos cómo queda algún elemento:
datos_graf[[2]]
## # A tibble: 688 x 5
## # Groups: SEXO, Ing_Ocup_Principal [150]
## SEXO Ing_Ocup_Principal Horas Casos sector
## <chr> <int> <int> <int> <fct>
## 1 Mujeres 2000 3 2107 Construccion
## 2 Mujeres 3000 20 269 Construccion
## 3 Mujeres 3500 25 25 Construccion
## 4 Mujeres 4000 40 141 Construccion
## 5 Mujeres 5000 8 391 Construccion
## 6 Mujeres 5000 10 654 Construccion
## 7 Mujeres 6000 8 37 Construccion
## 8 Mujeres 6400 15 268 Construccion
## 9 Mujeres 6500 15 290 Construccion
## 10 Mujeres 10000 30 1571 Construccion
## # ... with 678 more rows
Luego, creamos nuestra función que grafica la información de una tabla:
crear_grafico = function(tabla){
ggplot(tabla, aes(x = Horas, y = Ing_Ocup_Principal, size =Casos, color = SEXO)) +
geom_point(alpha = 0.4)+
theme_minimal()+
scale_color_manual(values = c("deeppink4","mediumseagreen"))+
scale_size_continuous(range = c(2, 15))+
scale_y_continuous(labels = function(x) paste0("$",x))+
facet_wrap(~SEXO, scales = "fixed", nrow = 1)+
labs(title = unique(tabla$sector),
y = "Ingreso de la ocupación principal",
x = "Horas semanales trabajadas",
color = "Sexo")+
theme(legend.position = "bottom")+
ggsave(paste0("clase6/graficos/",tolower(str_replace_all(unique(tabla$sector), " ", "_")),".png"))
}
Finalmente, la aplicamos de forma iterativa:
for (i in seq(length(datos_graf))) {
crear_grafico(datos_graf[[i]])
}
Los resultados de nuestro procesamiento están guardados en la carpeta graficos de la clase 6.
¡Terminamos! Ahora, vamos a la parte práctica.